package com.yzc.util;

import com.yzc.Details.SecurityUser;
import com.yzc.model.entity.system.SysUser;
import com.yzc.model.entity.util.JwtProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecurityException;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import java.security.Key;
import java.util.Date;

@Slf4j
@Component
@ConditionalOnProperty(name = "jwt.enabled", havingValue = "true")
@RequiredArgsConstructor  // Lombok 自动生成构造函数
public class JwtUtil {


    private final JwtProperties jwtProperties;
//    @Value("${jwt.secret}")
//    private String secret; // 需为Base64编码的密钥（推荐长度：32字节）

//    @Value("${jwt.expiration}") // 默认1小时（单位：毫秒）
//    private Long expiration;
    // 缓存签名密钥（线程安全）
    private volatile Key signingKey;

    public Long getExpirationMillis() {
        return jwtProperties.getExpiration();
    }

    // 生成安全的HMAC-SHA密钥（Base64解码）
    private Key getSigningKey() {
        if (signingKey == null) {                   //  在进入同步块之前，先检查 signingKey 是否为 null。
            synchronized (this) {                   //  同步块
                if (signingKey == null) {           //  在同步块内部，再次检查 signingKey 是否为 null
                    byte[] keyBytes = Decoders.BASE64.decode(jwtProperties.getSecret());   //  解码密钥字符串
                    signingKey = Keys.hmacShaKeyFor(keyBytes);          //  生成签名密钥
                    log.info("JWT签名密钥初始化完成");
                }
            }
        }
        return signingKey;
    }

    // 生成Token（包含用户ID和用户名）-----SysUser
    public String generateToken(SysUser user) {
        return Jwts.builder()
                .claim("userId", user.getId())//声明的键是 "userId"，值是 user.getId()
                .subject(user.getName())        //主题被设置为 user.getName()，即用户的名称
                .issuedAt(new Date())           //设置 JWT 的签发时间
                .expiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration()))  //设置 JWT 的过期时间
                .signWith(getSigningKey())      //于设置 JWT 的签名密钥
                .compact();                     //将构建好的 JWT 转换为一个紧凑的字符串格式(生成token)
    }
    // 生成Token（包含用户ID和用户名）---SecurityUser
    public String generateSecurityToken(SecurityUser user) {
        return Jwts.builder()
                .claim("userId", user.getId())//声明的键是 "userId"，值是 user.getId()
                .subject(user.getUsername())        //主题被设置为 user.getName()，即用户的名称
                .issuedAt(new Date())           //设置 JWT 的签发时间
                .expiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration()))  //设置 JWT 的过期时间
                .signWith(getSigningKey())      //于设置 JWT 的签名密钥
                .compact();                     //将构建好的 JWT 转换为一个紧凑的字符串格式(生成token)
    }

    // 提取用户ID
    public Long extractUserId(String token) {
        return parseClaims(token).get("userId", Long.class);
    }

    // 提取用户名
    public String extractUsername(String token) {
        return parseClaims(token).getSubject();
    }

    // 验证Token有效性（签名 + 过期时间）
    public boolean validateToken(String token) {
        try {
            Claims claims = parseClaims(token);                             // 解析并验证签名
            boolean expired = claims.getExpiration().before(new Date());    // 检查是否已过期
            if (expired) log.warn("Token已过期: {}", token);
            return !expired;
        } catch (ExpiredJwtException e) {
            log.warn("Token已过期: {}", e.getMessage());
            return false;
        } catch (SecurityException e) {
            log.warn("无效的JWT签名: {}", e.getMessage());
            return false;
        } catch (JwtException | IllegalArgumentException e) {
            log.warn("无效的JWT: {}", e.getMessage());
            return false;
        }
    }

    // 统一解析Claims（带异常抛出）
    private Claims parseClaims(String token) {
        return Jwts.parser()
                .verifyWith((SecretKey) getSigningKey())        // 设置验证密钥
                .build()
                .parseSignedClaims(token)                       // 解析并验证签名
                .getPayload();                                  // 提取 Payload（Claims,包含用户信息、过期时间等）
    }

    // 启动时校验配置
    @PostConstruct
    public void validateConfig() {
        if (!StringUtils.hasText(jwtProperties.getSecret())) {
            throw new IllegalStateException("jwt.secret 未配置");
        }
        try {
            getSigningKey(); // 触发密钥生成，验证格式是否正确
        } catch (Exception e) {
            throw new IllegalArgumentException("jwt.secret 格式错误，需为Base64编码的HMAC-SHA密钥", e);
        }
    }
    //解析Token jwt用
    public String resolveToken(String authHeader) {
        // 检查 Authorization 头是否非空且以 "Bearer " 开头
        if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);     //去掉前 7 个字符（即 Bearer）
        }
        return null;
    }
    //解析Token   security用
    public String resolveReqToken(HttpServletRequest request) {
        // 检查 Authorization 头是否非空且以 "Bearer " 开头
        String authHeader = request.getHeader("Authorization");
        if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7); // 去掉 "Bearer " 前缀
        }
        return null;
    }

}